Welcome back.
In this lecture, we'll be creating another tool that heals our player when they've lost health.
So when we click this tool as you can see we are healing ourself.
And then bam we get health added back to our character.
This tool will be very important for players when they're low on health and surrounded by zombies.
So let's go ahead and get started.
Inside server storage and inside of our tools folder, we have our med kit tool and we can go ahead
and change the parent of this med kit tool to be the child of our rig.
So that way you can see our rig has the med kit equipped, and then we can go ahead and create two animations
for our med kit.
We're going to need one animation for holding or having the med kit equipped.
And then we're going to need another animation for us to be applying the med kit to ourselves, so we
can go ahead and open up the animation editor again.
And then we can select our rig and create our new animation.
And again we'll want to have this animation last a total of one second across our timeline.
And we're going to be able to adjust the speed of the animation from our script for the equipped animation.
Mine is very simple.
I just have my arms bent out in front of me, holding the med kit with both hands, and we'll make sure
that we have this animation looped.
And then we'll also make sure we have the priority set to movement.
And then once you have your equipped animation completed, you can go ahead and publish it to the game
and make sure you save that ID for later because we're going to need it.
And then from this equip animation, you can go ahead and keep the exact same keyframe at the beginning
as well as at the end.
And then inside between those two keyframes, you can go ahead and start animating your healing animation.
So here I have my healing animation and I'll go ahead and play it for you.
As you can see, it's very fast because the timeline is only one second.
But again, we're going to adjust the speed of this animation to stretch it out over a longer period
of time.
Just setting it to one second makes it easier for us to calculate the exact duration that we want for
the animation, but as you can see, I've just customized it here a little bit.
I've changed up the easing style and the easing direction, and I've just had my character, you know,
move their arm around and their hand around to make it look like they're healing themselves.
And that's the whole animation.
Of course, you want to make sure that that kind of animation is not looped, and make sure your priority
is set to action.
And you can go ahead and publish it to Roblox.
And then once you're done publishing it again, you can copy that animation ID we're going to need it
for later.
If you would like to use these animations that I've created again, I'll have this rig attached to the
lecture that you can go ahead and grab, load the different animations on a rig and then publish them
to Roblox.
Now that we have our animations complete, we can go ahead and create a new module script inside of
our med kit, and we're going to do the exact same formula that we did for our knife.
We're going to call this module script our properties.
And inside of here I'll have a table called self.
And I'll make sure to return that at the end of my module script.
And inside of this table is where we can store all of the different properties for our med kit.
For example, one of those properties would be how much we would like to heal the player by.
So we could call this healing amount, and we could set it to a value of like 50 health points.
We can also define whether or not we would like this med kit to be a one time use med kit, or if the
player is able to use it over and over again.
So we could create a key.
I'll call it one use and I'm going to set it for true in this instance.
But we're going to script our med kit in a way where we can either let it be one use or not let it be
one use.
And if it's not going to be a one use med kit, then we can go ahead and define a cooldown for how long
we should wait between allowing the player to heal because we don't want the player to be able to spam
heal, so we can call this healing cooldown.
You can set it to whatever value, but since I don't want my med kit to be one use, I'm just going
to fill in some random value like one.
And we can have a section for our animations.
Again, we're going to want to have our equip animation.
So we'll store the ID for that there.
And then we also want to have our healing animation.
And then down here we can also define the animation duration for our healing animation.
And we could do something like maybe three seconds long.
So make sure you've grabbed your animation IDs and pasted them into the correct, uh, key value pair.
And now what we can do is we can go ahead and define the properties for the sound we would like to play
to heal the player.
So I'll call this healing sound Properties.
And inside of here I'll also store the sound ID, so that way we don't have to store it in a separate
property.
So we'll have the sound ID for the sound we can have the roll off max distance.
We'll set it to something like 35.
We'll have the roll off minimum distance.
That could be like 15 studs.
The roll off mode will be the enum dot roll off mode dot inverse tapered.
And then we could set the volume to like 0.25.
Now, I did find a good healing sound ID from the toolbox right here, so if you would like to use that
sound ID, you can go ahead and copy this number right here.
And also place it inside of your Healing sound properties.
And I'll go ahead and show you that sound as well.
I'll just create a temporary sound instance here, and I'll put that sound ID inside of it.
And then we can play the sound.
Very basic.
Now, as you can see, there is a little bit of a delay before the sound actually starts playing.
Maybe about half a second or a little bit longer of a delay before we actually start hearing the sound.
So what we can also do is inside of the healing sound properties, we can define the time position we
would set for the sound before we start playing it.
And we could set it to the value of like 0.8.
So that way when we play the sound, it's going to start at 0.8 seconds, and we don't have to sit there
and wait through that section of our sound that has no sound playing.
So I'll go over and define another key inside of this table, and I'll just call it time position and
set it to a value of like 0.8 seconds.
Now that we have our module script set up, we can go ahead and add the local script as well as the
server script that's going to be responsible for our med kit.
And I'm going to show you a different method of scripting your tool without having to need to use a
remote event.
So what we're going to do for this one is we're going to have the local script, listen to the activated
event and do its thing on the client side.
And then we're also going to have the server script listen to the activated event and do its own thing
on the server side.
So that way we don't have to use a remote event to communicate between the local script and the server
script.
You can use a remote event, but I'm going to show you this method as well to show you there's multiple
different ways we can approach solving a problem, such as trying to have two different scripts interact
with the same tool.
Inside of our local script, we're going to be using that exact same comment template that we've always
been using.
And we can go ahead and create several variables one to firstly reference the tool itself, which will
be equal to script dot parent.
And then we also want to get the properties for the tool.
So we'll require tool dot properties.
We'll also want to get our player.
So that means we're going to have to grab the player service.
So players is equal to game get service players.
So player is going to be equal to players dot local player.
And then we're going to need the player's character humanoid and animator.
That way we can load the animations on our player.
So our character is going to be equal to our player dot character.
And just in case the character has not been loaded yet, we'll do or player dot character added and
we'll wait.
Then we can get the humanoid in our character, so that'll be equal to the character weight for child
humanoid.
And then we can also get the animator.
So humanoid weight for child animator.
And now basically what we can do is we can go back to server storage and go back to our knife tool and
open up its local script, because I want to copy this code that we've done right here.
I'm just going to copy this and then exit out and go back to my local script and paste that in there,
because we're just going to be using the exact same function.
Because now I can get my equip track and we'll just call Create Track.
And that's going to be our properties dot equip animation.
So now I can go ahead and listen for when my tool is equipped.
I can also go ahead and listen for my tools.
Unequipped.
And then I can go ahead and listen for when my tool is activated.
And then in the equip section we want to make sure to play the equip track.
And then for this section, we want to make sure we stop playing the equip track when we don't have
the tool equipped anymore.
And then inside of the activated event, we can go ahead and create a variable.
I'll call it Healing Track.
And again we'll be using the Create Track function to create.
A animation track from the healing animation, and then we can play our healing track.
And then again, we're going to adjust the speed of our healing track to be equal to one divided by
our properties.
Dot animation duration.
And then when we can go ahead and do is listen for when our healing track has ended.
And we'll connect a function to that event.
And this is where we'll just destroy our healing track.
And this is where we would also perhaps set a debounce to be false.
So that way we're not like spam playing our healing animation.
So let's go ahead and create a variable for doing that.
I'll call it the healing Debounce set equal to false.
And then here we'll set healing debounce equal to true.
And then we'll check if healing debounce is true.
If it is, we'll return.
That way we don't spam play the same healing animation.
And then once our healing animation ends, we can set healing debounce back to false.
But we only want to set the healing debounce back to false after we have waited for our healing cooldown.
And that's just in case this med kit isn't a one time use med kit.
So what we can do is we can have an if statement and check if we do not have the property of one, use
set to true.
So if this is a med kit that can be reused multiple times, then we can go ahead and add a yield statement
and wait for that healing cooldown.
And then we can go ahead and set the healing debounce back to false.
Otherwise, if this med kit is a one time use, then we don't need to worry about healing debounce because
this entire tool will be destroyed by our server script.
So if we hop into our server script, we'll be using that exact same template as before.
And inside of here we're basically going to just need the tool which is script dot parent as well as
the properties for the tool.
So that'll be require tool dot properties.
And then we'll make sure to have a debounce on the server side as well.
And what we're going to want to do is we want to listen to when our tool is activated.
And here is where we'll set our healing balance equal to true.
And then we'll make sure if our healing de balance is already true, we just return.
Otherwise, we should play the healing sound and then wait for the player's animation to end.
And then afterwards we can go ahead and heal them.
So what we can do is we can actually go to our knife again, open up that server script, and we're
basically just going to copy the exact same function in here and then just use it in our other script
here because we need to create a sound.
So I'll create a variable, I'll call this my healing sound.
And it's going to be equal to create sound.
But I do not need to pass the ID here because the ID is contained in our sound properties.
So I'll just delete that.
And then we can go ahead and create our sound.
The parent will be we could do tool dot.
Andl.
And then the properties is going to be the healing sound properties.
Then we can go ahead and play our healing sound.
So healing sound play.
And then when our healing sound has ended, we'll connect a function and we will destroy the healing
sound.
And after we play the healing sound and we can go ahead and wait for the player to stop playing their
animation.
So we'll just use the animation duration.
This allows the server to keep a rough estimate of when the player's animation ends, and then what
we can go ahead and do is we want to make sure that the player still has their tool equipped the entire
time.
So in this yield statement right here in those three seconds, the player could have unequipped their
med kit.
So if they do not have their med kit still equipped after this yield statement, then we don't want
to heal that player.
So what we can do is we can check if the tool dot parent is equal to, or we can check the name if it's
equal to backpack.
So if it's not equal to backpack which means our player should have it equipped, then we can do tool
dot parent dot humanoid dot health is equal to.
And we're just going to set it plus equal the properties dot healing amount.
Otherwise, if the tool is inside of the backpack, then we'll just set healing debounce back to false
and then we're going to return.
We don't want to heal the player when they don't have it equipped, and then we need to check whether
or not this med kit is a one time use.
If it's not a one time use, then we're going to wait for our properties dot healing cooldown and then
we can set healing Debounce back to false.
Otherwise, if our med kit is a one time use, then we want to destroy it.
So we'll use tool and we'll call the destroy function.
And that's all we should need to do to create a healing med kit for our player.
So let's go ahead and test what we've gotten done so far.
We'll go ahead and grab our med kit and set its parent equal to our starter pack.
And then we can go and playtest our game.
And we'll click play.
And if I hold my med kit, perfect.
We have our animation plane and then let me go to the server and go in the workspace and let me go ahead
and set my health to one.
I'll go back to my player.
So I have very little health.
And then if I click, there we go.
I'm healing up.
And perfect.
The server gave me my health back.
Now, as you can see, there's an issue here where our animation is still playing.
So that means what we're going to have to do is we're going to have to listen on the client side, when
our tool is destroyed and when our tool is destroyed, then we can go ahead and stop playing our animation.
Because this is an issue.
We don't want to have our animation still playing on our player.
Now, the simplest way we could do this is just refer to our tool and listen to the destroying event
and connect a function to it.
And here we could just stop the equip track.
And then since we don't need the equip track anymore, we can go ahead and destroy the equip track.
Now you think this code would work fine and you would be right.
But actually, this code only works if the game is set to something called immediate signaling.
So I'm going to quickly go over to my workspace.
And inside of the properties panel you can see there is a setting right here called Signal Behavior.
And right now it's set to a signal behavior called deferred.
Now I'm not going to go into the topic and differences between immediate signaling and deferred signaling
as that's too advanced to discuss right now.
But just know that deferred events are going to be the future for the Roblox platform.
All games that you create will be set to deferred by default.
The issue with this is that it's going to break certain things in our scripts, such as trying to listen
to this destroying event for our tool from inside a script that is also being destroyed at the same
time.
This code would work fine with immediate events, but with deferred events, which is going to be the
default, we are going to have to do something a little bit different because this code is not going
to work.
Now, I've tried experimenting a little bit to try and figure out what would be the best solution for
stopping an animations when the tool is being destroyed within this local script that is inside of our
tool.
And the best solution that works that I've found so far is we're going to have to use the task library
and spawn a new thread.
And inside of this thread is we're going to have to yield the thread again.
So we're going to listen to the destroying event.
But we're going to use the wait function and yield the current thread until the signal fires.
And then once that signal fires, we can stop the clip track.
And then we can go ahead and destroy the equip track.
And this is what works with a deferred signaling enabled.
Now I don't know if this was done on purpose or is simply a mistake or a byproduct of deferred signaling,
so in the future they might fix it where this event will fire from the script.
But as it stands currently, this is not going to work with deferred signaling.
And since deferred signaling is the default for all games, now you're going to have to do it with this
method and I'll prove that to you.
Let me go ahead and set or let me keep signaling behavior set to deferred.
And I'm going to comment this chunk of code out.
And then we're going to playtest our game again.
And let me just activate and use my tool.
And you should see that my animation.
As you can see, my animation is still stuck on my character.
However, if I go and set the signal behavior to immediate.
I'll playtest my game.
And now we are getting another error because of immediate signaling.
Man, I really love Roblox.
Sometimes cannot load the animation clip provider service.
Don't worry, that's not a problem in our code.
This is a problem on Roblox end, and that's because it's giving us this error of cannot load the animation
clip provider service from our create track function, because we can only use or load animations on
a character when it's a descendant of the workspace.
So you might be thinking, well, wait, we're grabbing the player's character right here, or we're
waiting for it to be added.
Why are we getting this error?
Shouldn't our player be a descendant of the workspace?
And no, it isn't a descendant of the workspace for some reason.
So with immediate signaling, we're having this other issue of cannot load the animation clip provider
service.
And to fix that problem, another way you could do it is you could just refer to the workspace and then
wait for our player.
To be in the workspace.
This is the other solution you'd have to do for this error.
I know Roblox is being stupid sometimes.
This is what we have to deal with.
So in order for me to demonstrate immediate signal behavior, let me fix this problem and then we'll
go back and playtest our game again.
And hopefully we should have this problem fixed.
Okay, good.
The error is gone.
Okay.
There's our animation.
If we use the med kit.
Perfect.
As you can see, the animation ended and we're back in our normal, uh, idling animation for our player's
character.
So that's with immediate signaling.
But as you saw earlier with deferred signaling, it doesn't work.
Now, you could be thinking, well, why don't we just set the game to immediate signaling and not worry
about it?
And you would be right in that regard.
But since deferred signaling is being pushed as the new thing or the thing that's going to be preferred
in the future, I have a feeling that immediate signaling is probably going to be deprecated or at some
point in the future, removed.
So it's always good to be using the new thing, which is deferred signaling if you want to set it to
immediate and keep it out immediate, fine.
But I'm going to keep it at deferred because all games by default are going to be set to the deferred
signal behavior.
So let me go ahead and delete this because we're back in the deferred mode, which fixes that problem.
And then let me go ahead and show you the solution.
For the deferred signal behavior.
So this code right here is going to work with deferred signaling enabled.
So if we go and play test our game.
And we hop back in.
Now if I go ahead and use my med kit.
When we're done, perfect, the animation stops, so I don't know why that works the way it does.
I'm not a Roblox engineer and I don't know what they do under the hood in their engine.
Hopefully they fix this problem, but as it stands currently, this is the solution we have to employ
with their new deferred signal behavior.
I know we love Roblox so much when they make these changes.
Now, one last thing I want to address in our code is that you've noticed that we are able to use our
med kit even though we're at full health.
So if you want to avoid the player from accidentally using their med kit when they have full health,
that we can go back to our server script.
And what we want to do is we want to make sure that our player's character's health is not equal to
its max health.
So if we've lost health, then we can go ahead and use the med kit.
But let's say if our tool dot parent dot humanoid and the health if this is greater than or equal to
our tool dot parent dot humanoid and the max health property, then we're just going to return and we
can do this exact same thing on the client side as well to prevent the animation from playing.
So if our humanoids health property that's greater than or equal to the humanoids Max health property,
then we don't want to play the animation.
So now if we go and play test.
If I try to use my tool while I have full health, it shouldn't work.
So if I click as you can see, nothing is happening.
It isn't until I go to the server and I set my health to be very low, and then I go back that I am
now able to use my med kit.
And as you can see, and now I get health added back to my player's character.
Very cool.
Alrighty.
And that is how you can create a tool that heals the player.
Sorry about the issues we encountered earlier regarding deferred and immediate signaling.
This is just the problems we will encounter when Roblox makes these kinds of changes.
Otherwise, you're doing great so far on this project.
Keep up the good work and I'll see you in the next lecture.